
local skynet = require "skynet"
require "skynet.manager"
local mysql = require "skynet.db.mysql"

local utils = require "utils"

local slaves = {}
local save_queue = {} --taskid -> taskdata
local temp_queue = {}

local balance = 1
local taskid = 1
local runtask = 1

local function gettaskid()
	local id = taskid

	taskid = taskid + 1

	return id
end

local function getslave()
	local slave = slaves[balance]

	balance = balance + 1

	if balance > #slaves then
		balance = 1
	end

	return slave
end

local CMD = {}

function CMD.alter(name, data)
	-- local newtaskid = gettaskid()
	-- save_queue[newtaskid] = nil
	
	-- local task = {
	-- 	taskid = newtaskid,
	-- 	order = "alter",
	-- 	dbname = name,
	-- 	data = data,
	-- 	sended_to_slave = false,
	-- }

	-- save_queue[newtaskid] = task
	-- return true
	local slave = getslave()
	local ret = skynet.call(slave, "lua","alter",name,data)
	return ret
end

function CMD.insert(name, data)
	local newtaskid = gettaskid()
	save_queue[newtaskid] = nil
	
	local task = {
		taskid = newtaskid,
		order = "insert",
		dbname = name,
		data = data,
		sended_to_slave = false,
	}

	save_queue[newtaskid] = task
	return true
end


function CMD.update(name, data,order)
	local newtaskid = gettaskid()
	save_queue[newtaskid] = nil

	local temp = temp_queue[name..order]
	if temp ~= nil and temp.data ~= nil then
		for k, v in pairs(data) do
			if v ~= "NaN" then
				temp.data[k] = v
			end
		end
		save_queue[temp.taskid] = nil
		temp.taskid = newtaskid
		save_queue[newtaskid] = temp
		return
	end
	
	local task = {
		taskid = newtaskid,
		order = "update",
		dbname = name,
		data = data,
		secondorder = order,
		sended_to_slave = false,
	}

	save_queue[newtaskid] = task

	temp_queue[name..order] = task
	return true
end

function CMD.delete(name,order)
	local newtaskid = gettaskid()
	save_queue[newtaskid] = nil
	
	local task = {
		taskid = newtaskid,
		order = "delete",
		dbname = name,
		data = order,
		sended_to_slave = false,
	}

	save_queue[newtaskid] = task
	return true
end

function CMD.setData(name, data,uid)
	local newtaskid = gettaskid()
	save_queue[newtaskid] = nil

	local temp = temp_queue[name..uid]
	if temp ~= nil and temp.data ~= nil then
		for k, v in pairs(data) do
			if v ~= "NaN" then
				temp.data[k] = v
			end
		end
		save_queue[temp.taskid] = nil
		temp.taskid = newtaskid
		save_queue[newtaskid] = temp
		return
	end
	
	local task = {
		taskid = newtaskid,
		order = "setData",
		dbname = name,
		data = data,
		secondorder = "uid="..uid,
		sended_to_slave = false,
	}

	save_queue[newtaskid] = task

	temp_queue[name..uid] = task
	return true
end

local function process_task_queue()
	temp_queue = {}

	while runtask < taskid do
		-- print(runtask)
		local task = save_queue[runtask]
		if task and not task.sended_to_slave then
			local slave = getslave()
			skynet.send(slave, "lua", task.order,task.dbname, task.data,task.taskid
										,task.secondorder)
			task.sended_to_slave = true
		end
		runtask = runtask + 1
	end
	-- for taskid, task in pairs(save_queue) do
	-- 	if not task.sended_to_slave then
	-- 		local slave = getslave()
	-- 		skynet.send(slave, "lua", task.order,task.dbname, task.data,task.taskid
	-- 									,task.secondorder)
	-- 		task.sended_to_slave = true
	-- 	end
	-- end

	skynet.timeout(100, process_task_queue)
end

-- local function backupdata()
-- 	skynet.timeout((utils.getHourTime(3) - utils.time()) * 100, backupdata)
-- end

--called by persistent slave
function CMD.finish_task(taskid)
	local task = save_queue[taskid]

	if task then
		save_queue[taskid] = nil
	end
end

function CMD.getData(name, keys,order)
	local slave = getslave()
	local ret = skynet.call(slave, "lua","getData",name,keys,order )
	return ret
end

function CMD.checkKeyExist(name, id)
	local slave = getslave()
	local ret = skynet.call(slave, "lua",name,"*","id="..id )
	return ret
end

function CMD.create(name, value)
	local slave = getslave()
	local ret = skynet.call(slave, "lua","create",name,value)
	return ret
end


function CMD.executiveOrder(order)
	local slave = getslave()
	local ret = skynet.call(slave, "lua","executiveOrder",order)
	return ret
end


skynet.start(function()
	local slavesize = skynet.getenv("mysql_slave_poolsize") or 8
	slavesize = tonumber(slavesize)

	for i = 1, slavesize do
		slave = skynet.newservice("mysqlagent")
		skynet.call(slave, "lua", "init", skynet.self())

		slaves[#slaves + 1] = slave
	end

	skynet.dispatch("lua", function(session, source, cmd, ...)
		local f = assert(CMD[cmd])

		local ret = f(...)
		if ret ~= nil then
			skynet.ret(skynet.pack(ret))
		end
	end)

	skynet.timeout(100, process_task_queue)

	-- skynet.timeout(100, backupdata)

	skynet.register("mysqlserver")
end)
